package br.edu.ufcg.unknown.semantico;

import br.edu.ufcg.unknown.lexico.Token;
import br.edu.ufcg.unknown.sintatico.IdentificaTK;

public class Tipo implements Cloneable {

	public static final String T_CADEIA = "STRING";
	public static final String T_INTEIRO = "INTEGER";
	public static final String T_BOOLEANO = "BOOLEAN";
	
	public static final int TAM_MAXIMO_INTEIRO = 32767;
	public static final int TAM_MINIMO_INTEIRO = -32768;
	
	private String tipo;
	private boolean ehArray;
	private Token token;
	private int precedencia;
	private int indexArray;
	private static final IdentificaTK ident = new IdentificaTK();

	private static final String LINE_SEPARATOR = System.getProperty("line.separator");

	private Tipo() {
		
	}
	
	public Tipo(Token tk) {
		this(tk, false);
	}

	public Tipo(Token tk, boolean array) {
		setTipo(tk);
		setPrecedencia(tk);
		this.ehArray = array;
		this.token = tk;
		this.indexArray = 0;
	}

	public String getTipo() {
		return this.tipo;
	}
	
	public void setTipo(String tipo) {
		this.tipo = tipo;
	}

	public boolean ehArray() {
		return this.ehArray;
	}

	private void setTipo(Token tk) {
		if (tk.ehPalavraReservada() && !(ident.eh_TRUE(tk) || ident.eh_FALSE(tk))) {
			this.tipo = tk.getLexema();
		} else {
			if (ident.eh_ALFA(tk)) {
				this.tipo = T_CADEIA;
			} else if (ident.eh_NUM(tk)) {
				this.tipo = T_INTEIRO;
			} else if (ident.eh_TRUE(tk) || ident.eh_FALSE(tk)) {
				this.tipo = T_BOOLEANO;
			}
		}
	}

	public void setEhArray(boolean array) {
		this.ehArray = array;

	}

	public Token getToken() {
		return token;
	}

	public void setToken(Token token) {
		this.token = token;
	}

	// TODO Corrigir equals de TIPO ou então corrigir o resolvedor de Árvore. Pois da forma que está
	// sendo feita um token devolvido pelo resolvedor de árvore que seja do tipo INTEGER não vai
	// bater com uma variável que seja do mesmo tipo. Na verdade o problema é que o lexema lido "2"
	// tem o Tipo gerado de uma forma e o valor inteiro retornado do resolvedor de arvores tem outro
	// tipo, daí não iria bater os tipos na hora de fazer a verificação com o equals.
	public boolean equals(Tipo newTipo) {
		if (this.tipo != null && newTipo.tipo != null) {
			if (!this.tipo.equals(newTipo.tipo)) {
				return false;
			}
		} else if (this.tipo != null || newTipo.tipo != null) {
			return false;
		}

		return true;
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();

		sb.append("Tipo: ");
		sb.append(this.tipo);
		sb.append(LINE_SEPARATOR);
		sb.append("É array? ");
		sb.append(this.ehArray);
		sb.append(LINE_SEPARATOR);
		sb.append("Precedência: ");
		sb.append(this.precedencia);
		sb.append(LINE_SEPARATOR);
		sb.append("Token: ");
		sb.append(LINE_SEPARATOR);
		sb.append(this.token);

		return sb.toString();
	}

	public boolean ehInteger() {
		if (this.tipo == null) {
			return false;
		}
		return this.tipo.equals(T_INTEIRO);
	}

	public boolean ehCadeia() {
		if (this.tipo == null) {
			return false;
		}
		return this.tipo.equals(T_CADEIA);
	}

	public boolean ehBoolean() {
		if (this.tipo == null) {
			return false;
		}
		return this.tipo.equals(T_BOOLEANO);
	}

	private void setPrecedencia(Token tk) {
		this.precedencia = 0;
		if (tk.ehOperadorDivisao() || tk.ehOperadorMultiplicacao()) {
			this.precedencia += 4;
		} else if (tk.ehOperadorAdicao() || tk.ehOperadorSubtracao()) {
			this.precedencia += 3;
		} else if (tk.ehOperadorRelacional()) {
			this.precedencia += 2;
		} else if (ident.eh_DIFERENTE(tk)) {
			this.precedencia += 1;
		}
	}

	public int getPrecedencia() {
		return precedencia;
	}

	public Tipo clone(){
		Tipo r = new Tipo();
		r.ehArray = this.ehArray;
		r.precedencia = this.precedencia;
		r.tipo = this.tipo;
		r.token = this.token != null ? this.token.clone() : null;
		r.indexArray = this.indexArray;
		return r;
	}

	public void setIndexArray(int index) {
		this.indexArray = index;
	}
	
	public int getIndexArray() {
		return this.indexArray;
	}
	
	
	
	
}
